package tray

import (
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"runtime"
	"sync"
	"time"

	"goEmqxToDb/handler"
	"goEmqxToDb/mqtt"
	"goEmqxToDb/web"

	"github.com/getlantern/systray"
)

var (
	// 全局变量
	mqttClient     *mqtt.Client
	messageHandler *handler.MessageHandler
	isSubscribed   bool
	mu             sync.Mutex
	// 添加退出通道
	quitChan chan struct{}
	// 添加退出标志
	quitting bool
	quitMu   sync.Mutex
)

// RunTray 启动Windows系统托盘
func RunTray() {
	quitChan = make(chan struct{})
	quitting = false
	systray.Run(onReady, onExit)
}

// onReady 托盘准备就绪时的回调
func onReady() {
	// 设置图标
	iconData, err := ioutil.ReadFile("img/favicon.ico")
	if err != nil {
		log.Printf("无法读取图标文件: %v", err)
		// 使用默认图标
		systray.SetIcon(getDefaultIcon())
		log.Println("使用默认图标")
	} else {
		systray.SetIcon(iconData)
		log.Println("使用自定义图标: img/favicon.ico")
	}

	systray.SetTitle("MQTT数据采集工具")
	systray.SetTooltip("MQTT数据采集工具")

	// 添加菜单项
	mStatus := systray.AddMenuItem("状态: 未连接", "当前连接状态")
	mStatus.Disable() // 禁用状态菜单项

	systray.AddSeparator()

	// 订阅相关菜单项
	mSubscribe := systray.AddMenuItem("订阅主题", "开始订阅MQTT主题")
	mUnsubscribe := systray.AddMenuItem("取消订阅", "停止订阅MQTT主题")
	mUnsubscribe.Hide() // 初始隐藏取消订阅选项

	systray.AddSeparator()

	mShowLog := systray.AddMenuItem("显示日志", "显示应用程序日志")
	mEditConfig := systray.AddMenuItem("编辑配置", "打开配置文件进行编辑")
	mRestart := systray.AddMenuItem("重启应用", "重启应用程序")
	mReloadConfig := systray.AddMenuItem("重新加载配置", "重新加载配置文件")

	systray.AddSeparator()

	mQuit := systray.AddMenuItem("退出", "退出应用程序")

	// 启动后台服务
	go runBackgroundService()

	// 处理菜单点击事件
	go func() {
		for {
			select {
			case <-mSubscribe.ClickedCh:
				log.Println("收到订阅主题点击事件")
				go handleSubscribe(mStatus, mSubscribe, mUnsubscribe)
			case <-mUnsubscribe.ClickedCh:
				log.Println("收到取消订阅点击事件")
				go handleUnsubscribe(mStatus, mSubscribe, mUnsubscribe)
			case <-mShowLog.ClickedCh:
				log.Println("点击了显示日志")
				// 这里可以添加显示日志的逻辑
			case <-mEditConfig.ClickedCh:
				log.Println("点击了编辑配置")
				go handleEditConfig()
			case <-mRestart.ClickedCh:
				log.Println("点击了重启应用")
				// 这里可以添加重启逻辑
			case <-mReloadConfig.ClickedCh:
				log.Println("点击了重新加载配置")
				// 重新加载配置
				if isSubscribed {
					log.Println("当前已连接，先断开连接")
					handleUnsubscribe(mStatus, mSubscribe, mUnsubscribe)
				}
				log.Println("配置已重新加载，请重新订阅以使用新配置")
			case <-mQuit.ClickedCh:
				log.Println("点击了退出应用")
				// 设置退出标志
				quitMu.Lock()
				if !quitting {
					quitting = true
					// 发送退出信号
					if quitChan != nil {
						close(quitChan)
					}
				}
				quitMu.Unlock()
				// 断开MQTT连接
				if mqttClient != nil {
					mqttClient.Disconnect()
				}
				// 关闭消息处理器
				if messageHandler != nil {
					messageHandler.Close()
				}
				systray.Quit()
				return
			case <-quitChan:
				log.Println("收到退出信号")
				return
			}
		}
	}()
}

// handleSubscribe 处理订阅主题
func handleSubscribe(mStatus, mSubscribe, mUnsubscribe *systray.MenuItem) {
	log.Println("开始处理订阅主题...")

	mu.Lock()
	defer mu.Unlock()

	// 检查是否正在退出
	quitMu.Lock()
	if quitting {
		quitMu.Unlock()
		log.Println("程序正在退出，取消订阅操作")
		return
	}
	quitMu.Unlock()

	if isSubscribed {
		log.Println("已经处于订阅状态")
		return
	}

	log.Println("开始订阅主题...")

	// 创建MQTT客户端
	log.Println("正在创建MQTT客户端...")
	var err error
	mqttClient, err = mqtt.NewClient()
	if err != nil {
		log.Printf("创建MQTT客户端失败: %v", err)
		showError("创建MQTT客户端失败", err.Error())
		return
	}
	log.Println("MQTT客户端创建成功")

	// 连接到MQTT服务器
	log.Println("正在连接MQTT服务器...")

	// 在连接过程中检查退出状态
	connectDone := make(chan error, 1)
	go func() {
		err := mqttClient.Connect()
		connectDone <- err
	}()

	// 等待连接完成或退出
	select {
	case err := <-connectDone:
		if err != nil {
			log.Printf("连接MQTT服务器失败: %v", err)
			showError("连接MQTT服务器失败", err.Error())
			return
		}
	case <-quitChan:
		log.Println("用户取消连接操作")
		return
	}

	log.Println("MQTT服务器连接成功")

	// 创建消息处理器
	log.Println("正在创建消息处理器...")
	messageHandler = handler.NewMessageHandler(mqttClient)
	log.Println("消息处理器创建成功")

	// 订阅主题
	log.Println("正在订阅主题...")
	err = mqttClient.Subscribe(messageHandler.HandleMessage)
	if err != nil {
		log.Printf("订阅主题失败: %v", err)
		showError("订阅主题失败", err.Error())
		mqttClient.Disconnect()
		return
	}
	log.Println("主题订阅成功")

	// 再次检查是否正在退出
	quitMu.Lock()
	if quitting {
		quitMu.Unlock()
		log.Println("程序正在退出，清理已创建的连接")
		if mqttClient != nil {
			mqttClient.Disconnect()
		}
		if messageHandler != nil {
			messageHandler.Close()
		}
		return
	}
	quitMu.Unlock()

	// 更新状态
	isSubscribed = true
	mStatus.SetTitle("状态: 已连接")
	mStatus.SetTooltip("已连接到MQTT服务器并订阅主题")

	// 切换菜单显示
	log.Println("隐藏订阅菜单项，显示取消订阅菜单项")
	mSubscribe.Hide()
	mUnsubscribe.Show()

	// 恢复正常的工具提示
	systray.SetTooltip("MQTT数据采集工具")

	log.Println("成功订阅主题，开始接收消息...")
}

// handleUnsubscribe 处理取消订阅
func handleUnsubscribe(mStatus, mSubscribe, mUnsubscribe *systray.MenuItem) {
	log.Println("开始处理取消订阅...")

	mu.Lock()
	defer mu.Unlock()

	if !isSubscribed {
		log.Println("当前未处于订阅状态")
		return
	}

	log.Println("取消订阅主题...")

	// 关闭消息处理器
	if messageHandler != nil {
		messageHandler.Close()
		messageHandler = nil
	}

	// 断开MQTT连接
	if mqttClient != nil {
		mqttClient.Disconnect()
		mqttClient = nil
	}

	// 更新状态
	isSubscribed = false
	mStatus.SetTitle("状态: 未连接")
	mStatus.SetTooltip("未连接到MQTT服务器")

	// 切换菜单显示
	log.Println("隐藏取消订阅菜单项，显示订阅菜单项")
	mUnsubscribe.Hide()
	mSubscribe.Show()

	log.Println("已取消订阅并断开连接")
}

// showError 显示错误提示
func showError(title, message string) {
	log.Printf("错误 - %s: %s", title, message)
	// 使用系统托盘工具提示显示错误
	systray.SetTooltip("MQTT数据采集工具\n错误: " + title)
	// 这里可以扩展为使用Windows系统通知
}

// onExit 托盘退出时的回调
func onExit() {
	log.Println("托盘正在退出...")

	// 设置退出标志
	quitMu.Lock()
	if !quitting {
		quitting = true
		// 发送退出信号
		if quitChan != nil {
			close(quitChan)
		}
	}
	quitMu.Unlock()

	// 关闭消息处理器
	if messageHandler != nil {
		messageHandler.Close()
	}
	// 确保断开MQTT连接
	if mqttClient != nil {
		mqttClient.Disconnect()
	}
	// 等待一下确保资源清理完成
	time.Sleep(500 * time.Millisecond)

	// 强制退出，确保应用完全关闭
	log.Println("应用正在强制退出...")
	os.Exit(0)
}

// runBackgroundService 在托盘模式下运行后台服务
func runBackgroundService() {
	log.Println("托盘模式下的后台服务已启动")
	// 这里可以调用service.Run()中的业务逻辑
	// 或者直接在这里实现业务逻辑
}

// handleEditConfig 处理编辑配置
func handleEditConfig() {
	// 启动Web服务器
	go func() {
		server := web.NewServer(8080)
		if err := server.Start(); err != nil {
			log.Printf("启动Web服务器失败: %v", err)
		}
	}()

	// 等待一下让服务器启动
	time.Sleep(1 * time.Second)

	// 打开浏览器
	url := "http://localhost:8080"
	log.Printf("正在打开配置编辑器: %s", url)

	var cmd *exec.Cmd
	switch runtime.GOOS {
	case "windows":
		cmd = exec.Command("cmd", "/c", "start", "", url)
	case "darwin":
		cmd = exec.Command("open", url)
	default: // linux
		cmd = exec.Command("xdg-open", url)
	}

	if err := cmd.Run(); err != nil {
		log.Printf("打开浏览器失败: %v", err)
		// 尝试使用默认浏览器
		if runtime.GOOS == "windows" {
			cmd = exec.Command("explorer", url)
			if err := cmd.Run(); err != nil {
				log.Printf("使用explorer打开也失败: %v", err)
			} else {
				log.Println("使用explorer打开配置编辑器成功")
			}
		}
	} else {
		log.Println("配置编辑器打开成功")
	}
}

// getDefaultIcon 返回默认图标数据
func getDefaultIcon() []byte {
	// 这是一个简单的默认图标数据（1x1像素的透明PNG）
	return []byte{
		0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
		0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
		0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x15, 0xc4, 0x89, 0x00, 0x00, 0x00,
		0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x63, 0x00, 0x01, 0x00, 0x00,
		0x05, 0x00, 0x01, 0x0d, 0x0a, 0x2d, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x49,
		0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
	}
}
